package org.javaboy.demo.config;

import org.javaboy.demo.model.Book;
import org.javaboy.demo.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * 这个配置类的作用就相当于是 applicationContext.xml 这个配置文件的作用
 *
 * @Configuration：
 * 作用：添加了这个注解之后，如果调用到一个标记了 @Bean 注解的方法，那么这个方法不会被立马调用，而是先去 Spring 容器中
 * 检查这个 Bean 是否存在，如果存在，则直接返回，那么目标方法就不调用了。如果Spring容器不存在这个 Bean，则这个时候会执行目标
 * 方法，并且向 Spring 容器注册这个 Bean。
 * 实现的原理：AOP 代理
 */
@Configuration
public class JavaConfig {

    /**
     * 这里 @Bean 的作用类似于刚才的 bean 标签，就表示向 Spring 容器中注册一个 Bean
     * 默认情况下，beanName 就是方法名
     *
     * @return
     * @Bean 注解中也有 name 表示表示为这个 bean 指定名称
     * initMethod 和 destroyMethod 为这个 bean 指定生命周期钩子函数
     *
     * 可以直接在方法参数中指明想要的参数
     * 由于这个 user 方法是由 Spring 容器去调用的，所以 Spring 容器会去自动查找这个方法所需要的参数，然后才会去执行目标方法
     *
     * autowireCandidate 表示这个 Bean 是否作为注入的候选的 Bean
     * 这个属性为 false 就表示这个 Bean 不作为候选 Bean，即其他 Bean 需要注入 User 的时候，不会查找到这个 Bean
     */
    @Bean(value = "user",autowireCandidate = false)
    /**
     * 这个注解可以用来标记 Bean 的优先级，如果通过类型去 Spring 容器中查找 Bean 的话，
     * 那么标记了该注解的 Bean 会被优先返回。
     */
    @Primary
    User user(Book book) {
        User user = new User();
        user.setId(1);
        user.setUsername("zhangsan");
        user.setBook(book);
        return user;
    }

    @Bean
    User user2() {
        User user = new User();
        user.setUsername("lisi");
        return user;
    }

    @Bean
    Book book() {
        Book book = new Book();
        book.setName("三国演义");
        book.setAuthor("罗贯中");
        return book;
    }
}
